{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Making A Structured TTRPG Story with simpleaichat\n",
    "\n",
    "An update to ChatGPT on June 13th, 2023 allows the user to set a predefined schema to have ChatGPT output data according to that schema and/or take in an input schema and respond better to that data. This \"function calling\" as OpenAI calls it can be used as a form of tools, but the schema, enabled by a JSON-finetuning of ChatGPT, is much more useful for typical generative AI use cases, particularly when not using GPT-4.\n",
    "\n",
    "OpenAI's [official demos](https://github.com/openai/openai-cookbook/blob/main/examples/How_to_call_functions_with_chat_models.ipynb) for this feature are complicated, but with simpleaichat, it's very easy to support placing your own data\n",
    "\n",
    "**NOTE: Ensuring input and output follows a complex predefined structure is very new in the field of prompt engineering and although it is very powerful, your mileage may vary.**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install -q simpleaichat\n",
    "\n",
    "from simpleaichat import AIChat\n",
    "import orjson\n",
    "from rich.console import Console\n",
    "from getpass import getpass\n",
    "\n",
    "from typing import List, Literal, Optional, Union\n",
    "from pydantic import BaseModel, Field"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For the following cell, input your OpenAI API key when prompted. **It will not be saved to the notebook**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "api_key = getpass(\"OpenAI Key: \")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating a TTRPG the old-fashioned ChatGPT way\n",
    "\n",
    "Let's first create a TTRPG setting using the typical workflows of simpleaichat and ChatGPT with system prompt engineering.\n",
    "\n",
    "For this demo, we'll create a TTRPG about **Python software development** and **beach volleyball**. \n",
    "\n",
    "Yes, really. At the least, the resulting TTRPG will be _unique_.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "system_prompt = \"\"\"You are a world-renowned game master (GM) of tabletop role-playing games (RPGs).\n",
    "\n",
    "Write a setting description and two character sheets for the setting the user provides.\n",
    "\n",
    "Rules you MUST follow:\n",
    "- Always write in the style of 80's fantasy novels.\n",
    "- All names you create must be creative and unique. Always subvert expectations.\n",
    "- Include as much information as possible in your response.\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = \"gpt-3.5-turbo-0613\"\n",
    "ai = AIChat(system=system_prompt, model=model, save_messages=False, api_key=api_key)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The Legend of Zephyrus: Sands of Serpentia\n",
      "\n",
      "Welcome, brave adventurers, to the mystical realm of Serpentia, a land where the art of Python software development intertwines with the fierce battles of beach volleyball. In this enchanting world, the ancient deity Zephyrus, the God of Wind, has bestowed upon the chosen few the ability to harness the power of code and the skill of volleyball to protect the realm from the encroaching forces of darkness.\n",
      "\n",
      "Setting Description:\n",
      "\n",
      "Serpentia is a vibrant land filled with lush palm trees, golden sandy beaches, and crystal-clear turquoise waters. The sun shines brightly overhead, casting a warm glow upon the land. The realm is divided into three main regions:\n",
      "\n",
      "1. Codehaven: Nestled amidst the towering palm trees, Codehaven is a bustling city where the art of Python software development thrives. Here, the streets are lined with grand libraries and bustling marketplaces, where scribes and scholars exchange knowledge and trade powerful artifacts imbued with magical code. The air is filled with the soft hum of spells being cast and the rhythmic sound of keyboards clacking.\n",
      "\n",
      "2. Volleyshore: As you venture down the coastline, the serene beaches of Volleyshore come into view. This coastal region is renowned for its beach volleyball tournaments, where skilled players from all corners of Serpentia gather to showcase their talents. The sand sparkles in the sunlight, and the cheers of the crowd echo through the air as powerful spikes and agile dives bring the matches to life.\n",
      "\n",
      "3. Binary Peaks: Beyond the sprawling beaches lie the majestic Binary Peaks, a mountain range shrouded in mist and mystery. Within the peaks lies an ancient temple, said to be the birthplace of Zephyrus himself. It is a treacherous journey to reach the temple, but those who succeed are granted incredible powers and insights into the realm's deepest secrets.\n",
      "\n",
      "Character Sheets:\n",
      "\n",
      "1. Name: Cedric Windrider\n",
      "   Class: Python Sorcerer\n",
      "\n",
      "   Background: Cedric hails from a long line of esteemed Python sorcerers and is known for his unparalleled mastery over the arcane coding arts. With his flowing robes and a staff adorned with intricate Python symbols, Cedric is a true force to be reckoned with. His spells can manipulate data, summon algorithms, and even control the very fabric of the digital realm. He seeks to bring balance to Serpentia by merging his coding prowess with the skills of beach volleyball.\n",
      "\n",
      "   Abilities:\n",
      "   - Code Mastery: Cedric can effortlessly conjure complex Python spells, delving deep into the realm's digital architecture to bend it to his will.\n",
      "   - Volleyball Technique: Cedric has honed his volleyball skills, combining precise serves, spikes, and blocks with his magical abilities to dominate the court.\n",
      "\n",
      "2. Name: Astrid Sunstrike\n",
      "   Class: Volleyblade Ranger\n",
      "\n",
      "   Background: Astrid is a fierce and agile warrior who wields her volleyball racket with deadly precision. Born in the coastal town of Volleyshore, she has trained relentlessly to become a Volleyblade Ranger, a warrior who blends the grace of beach volleyball with the art of swordplay. Clad in light armor and with her trusty racket, Astrid is a formidable opponent both on the battlefield and the volleyball court.\n",
      "\n",
      "   Abilities:\n",
      "   - Volleyblade Mastery: Astrid's skilled swings and spins with her racket can slice through the air, sending powerful shockwaves towards her enemies or redirecting incoming projectiles.\n",
      "   - Agile Footwork: Astrid's training in beach volleyball has honed her agility, allowing her to dodge attacks and maneuver swiftly on the sand, gaining a tactical advantage in battles and matches alike.\n",
      "\n",
      "Prepare yourselves, brave adventurers, as you embark on an epic journey through the magical realm of Serpentia, where the realms of Python software development and beach volleyball collide. Harness the powers of code and the skills of the court to save the realm from the encroaching darkness and become legends in The Legend of Zephyrus: Sands of Serpentia!\n"
     ]
    }
   ],
   "source": [
    "response = ai(\"Python software development and beach volleyball\")\n",
    "print(response)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Evocative, but a bit disorganized. If we instead allow for structured data output that follows specifications, then we'll have a lot more flexibility both in terms of directing generation, and playing with the resulting output.\n",
    "\n",
    "That's where the `schema_output` field comes in when generating. If you construct a schema with pydantic ,which is also installed with simpleaichat as it is used heavily internally, then the output will generally follow the schema you provide!\n",
    "\n",
    "We want an output containing the setting **name** and **description**, along with a list of player characters. Since each character has its own attributes, and we may want the model to generate multiple chatacters, we'll define a schema for that first.\n",
    "\n",
    "We must also set a description for each field, can provide further hints to ChatGPT for how to guide generation. There is a _lot_ of flexibility here!\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class player_character(BaseModel):\n",
    "    name: str = Field(description=\"Character name\")\n",
    "    race: str = Field(description=\"Character race\")\n",
    "    job: str = Field(description=\"Character class/job\")\n",
    "    story: str = Field(description=\"Three-sentence character history\")\n",
    "    feats: List[str] = Field(description=\"Character feats\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An important note: with this new ChatGPT model, the fields are generated _in order_ at runtime according to the schema. Therefore, the order of the fields specified is important! Try to chain information!\n",
    "\n",
    "Now we can build the schema for the TTRPG we will send to ChatGPT. In this case, we will order the fields such that we generate `description` and then `name`, as the former will be more imaginative and the latter can be infered from it. We will also add a list of player characters using the player character schema above.\n",
    "\n",
    "Lastly, we will also include a docstring for the schema class; the specifics don't matter but it can provide another editorial hint.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class write_ttrpg_setting(BaseModel):\n",
    "    \"\"\"Write a fun and innovative TTRPG\"\"\"\n",
    "\n",
    "    description: str = Field(\n",
    "        description=\"Detailed description of the setting in the voice of the DM\"\n",
    "    )\n",
    "    name: str = Field(description=\"Name of the setting\")\n",
    "    pcs: List[player_character] = Field(description=\"Player characters of the TTRPG\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"description\": \"Welcome to the sun-kissed shores of Pythos, a land where software development and beach volleyball intertwine. In this unique setting, the power of Python programming and the thrill of competitive sports combine to create an unforgettable adventure. The land of Pythos is known for its pristine beaches, crystal-clear waters, and thriving tech industry. The locals, known as the Code Warriors, rely on their exceptional coding skills to develop cutting-edge software and maintain the digital infrastructure of the realm. But it's not all work and no play in Pythos. The Code Warriors also indulge in their passion for beach volleyball, competing in intense matches with rival teams from neighboring lands. As a player in this TTRPG, you will embark on a journey to master the art of Python software development and become a legendary beach volleyball player. Are you ready to dive into the world of Pythos?\",\n",
      "  \"name\": \"Pythos: Code Warriors\",\n",
      "  \"pcs\": [\n",
      "    {\n",
      "      \"name\": \"Aurora\",\n",
      "      \"race\": \"Human\",\n",
      "      \"job\": \"Python Developer\",\n",
      "      \"story\": \"Aurora is a talented programmer who grew up in the bustling city of Pythopolis. From a young age, she displayed an aptitude for coding and quickly rose through the ranks of the tech industry. However, she yearned for something more than just a desk job. Inspired by the Code Warriors, Aurora decided to combine her passion for programming with her love for beach volleyball. With her analytical mind and nimble fingers, she hopes to revolutionize the sport with her innovative Python-powered techniques.\",\n",
      "      \"feats\": [\n",
      "        \"Pythonic Precision: Aurora's code is elegant and efficient, allowing her to execute complex strategies with ease.\",\n",
      "        \"Volleyball Virtuoso: Aurora's exceptional hand-eye coordination and quick reflexes make her a formidable opponent on the beach volleyball court.\",\n",
      "        \"Tech Savant: Aurora has an encyclopedic knowledge of Python libraries and frameworks, giving her an edge in both software development and game analysis.\"\n",
      "      ]\n",
      "    },\n",
      "    {\n",
      "      \"name\": \"Blaze\",\n",
      "      \"race\": \"Elf\",\n",
      "      \"job\": \"Volleyball Coach\",\n",
      "      \"story\": \"Blaze is a wise and experienced elf who has dedicated his life to coaching aspiring beach volleyball players. He possesses an intimate understanding of the game and its intricacies, having spent centuries honing his skills on the sandy courts of Pythos. Blaze believes that the fusion of technology and sports is the key to unlocking the true potential of beach volleyball. As a coach, he imparts his wisdom to the Code Warriors, helping them master both the physical and digital aspects of the game.\",\n",
      "      \"feats\": [\n",
      "        \"Master Strategist: Blaze's strategic mind allows him to devise ingenious game plans that exploit the weaknesses of any opponent.\",\n",
      "        \"Eternal Youth: As an elf, Blaze's agelessness grants him unrivaled stamina, agility, and reflexes on the volleyball court.\",\n",
      "        \"Tech Guru: Blaze possesses a deep understanding of Python programming and uses it to analyze match data and optimize training routines.\"\n",
      "      ]\n",
      "    }\n",
      "  ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "response_structured = ai(\n",
    "    \"Python software development and beach volleyball\", output_schema=write_ttrpg_setting\n",
    ")\n",
    "\n",
    "# orjson.dumps preserves field order from the ChatGPT API\n",
    "print(orjson.dumps(response_structured, option=orjson.OPT_INDENT_2).decode())"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since the output is structured, we can parse it as we want.\n",
    "\n",
    "For example, if we just want the setting name:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Pythos: Code Warriors'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "response_structured[\"name\"]"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or if we just the names of the player characters:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Aurora', 'Blaze']"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[x[\"name\"] for x in response_structured[\"pcs\"]]"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Structured Output and Structured Input\n",
    "\n",
    "Now that we have a schema for a TTRPG setting, we can use the same hints we defined to help generation of a TTRPG adventure!\n",
    "\n",
    "First, we convert the structured `dict` data to a pydantic object with that schema with `parse_obj`:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "input_ttrpg = write_ttrpg_setting.model_validate(response_structured)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we define a schema for a list of events. To keep things simple, we'll just do **dialogue** and **setting** events. (a proper TTRPG would likely have a more detailed combat system!)\n",
    "\n",
    "There are a few other helpful object types you can use to control output:\n",
    "\n",
    "- `Literal`, to force a certain range of values.\n",
    "- `Union` can be used to have the model select from a set of schema. For example we have one schema for `Dialogue` and one schema for `Setting`: if unioned, the model will use only one of them, which allows for token-saving output.\n",
    "\n",
    "Lastly, if the `Field(description=...)` pattern is too wordy, you can use `fd` which is a shortcut.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "from simpleaichat.utils import fd\n",
    "\n",
    "\n",
    "class Dialogue(BaseModel):\n",
    "    character_name: str = fd(\"Character name\")\n",
    "    dialogue: str = fd(\"Dialogue from the character\")\n",
    "\n",
    "\n",
    "class Setting(BaseModel):\n",
    "    description: str = fd(\n",
    "        \"Detailed setting or event description, e.g. The sun was bright.\"\n",
    "    )\n",
    "\n",
    "\n",
    "class Event(BaseModel):\n",
    "    type: Literal[\"setting\", \"conversation\"] = fd(\n",
    "        \"Whether the event is a scene setting or a conversation by an NPC\"\n",
    "    )\n",
    "    data: Union[Dialogue, Setting] = fd(\"Event data\")\n",
    "\n",
    "\n",
    "class write_ttrpg_story(BaseModel):\n",
    "    \"\"\"Write an award-winning TTRPG story\"\"\"\n",
    "\n",
    "    events: List[Event] = fd(\"All events in a TTRPG campaign.\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lastly, we'll need a new system prompt since we have a different goal.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "system_prompt_event = \"\"\"You are a world-renowned game master (GM) of tabletop role-playing games (RPGs).\n",
    "\n",
    "Write a complete three-act story in 10 events with a shocking twist ending using the data from the input_ttrpg function. Write the player characters as a TTRPG party fighting against a new evil.\n",
    "\n",
    "In the second (2nd) event, the party must be formed.\n",
    "\n",
    "Rules you MUST follow:\n",
    "- Always write in the style of 80's fantasy novels.\n",
    "- All names you create must be creative and unique. Always subvert expectations.\"\"\""
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For the final call, we will need the parsed `input_ttrpg` object as the new \"prompt\", plus the `write_ttrpg_setting` schema used to build it as the `input_schema`.\n",
    "\n",
    "Putting it all together:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"events\": [\n",
      "    {\n",
      "      \"type\": \"setting\",\n",
      "      \"data\": {\n",
      "        \"description\": \"The sun rises over the golden shores of Pythos, casting a warm glow on the city of Pythopolis. The bustling metropolis is a hub of technology and beach volleyball, where the Code Warriors, a group of talented programmers and volleyball enthusiasts, reside. In the heart of the city, the Code Warriors' headquarters stands tall, a symbol of their dedication to both software development and sports. Inside, Aurora, a talented Python developer, and Blaze, a wise volleyball coach, prepare for a fateful meeting that will change their lives forever.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Aurora\",\n",
      "        \"dialogue\": \"Blaze, I've been following your coaching career for years. Your innovative techniques have revolutionized the game of beach volleyball. I want to combine my programming skills with my love for volleyball, and I believe you can help me become the best.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Blaze\",\n",
      "        \"dialogue\": \"Ah, Aurora, I've heard of your coding prowess. Your Python skills are legendary in the tech industry. If you're willing to put in the work, I can help you unlock the true potential of beach volleyball. Together, we can create a new era of sports technology.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Aurora\",\n",
      "        \"dialogue\": \"I'm ready to dive in, Blaze. I want to use Python to analyze the game, develop new strategies, and push the boundaries of what's possible on the court.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Blaze\",\n",
      "        \"dialogue\": \"Then we shall embark on this journey together, Aurora. But first, we must gather a team of like-minded individuals who share our passion for both programming and beach volleyball.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"setting\",\n",
      "      \"data\": {\n",
      "        \"description\": \"Aurora and Blaze set out on a quest to recruit the most talented individuals in Pythopolis. They scour the tech hubs, beachside cafes, and coding competitions, seeking those who possess the perfect blend of coding skills and volleyball prowess. After weeks of searching, they finally assemble a team of four exceptional individuals who are ready to join their cause.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Aurora\",\n",
      "        \"dialogue\": \"Welcome, my fellow Code Warriors! Together, we will combine the power of Python programming and the art of beach volleyball to achieve greatness. Introduce yourselves, and let us know how you plan to contribute to our mission.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Samurai\",\n",
      "        \"dialogue\": \"I am Samurai, a master of precision and discipline. My coding skills are unmatched, and my agility on the volleyball court is unparalleled. With my strategic mind and lightning-fast reflexes, I will ensure victory for our team.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Pixel\",\n",
      "        \"dialogue\": \"Greetings, Code Warriors! I am Pixel, the pixel-perfect programmer. My attention to detail and creative problem-solving abilities make me a valuable asset to any team. On the volleyball court, my quick thinking and adaptability will outwit our opponents.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Nebula\",\n",
      "        \"dialogue\": \"I am Nebula, a cosmic coder with a passion for the stars and the digital realm. My expertise lies in data analysis and visualization. I will harness the power of Python to uncover hidden patterns in our opponents' strategies and guide us to victory.\"\n",
      "      }\n",
      "    },\n",
      "    {\n",
      "      \"type\": \"conversation\",\n",
      "      \"data\": {\n",
      "        \"character_name\": \"Blitz\",\n",
      "        \"dialogue\": \"Greetings, Code Warriors! I am Blitz, the lightning-fast developer. My coding speed is unmatched, and my agility on the volleyball court is electrifying. With my lightning-quick reflexes and powerful spikes, I will leave our opponents in awe.\"\n",
      "      }\n",
      "    }\n",
      "  ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "ai_2 = AIChat(system=system_prompt_event, model=model, save_messages=False, api_key=api_key)\n",
    "\n",
    "response_story = ai_2(\n",
    "    input_ttrpg, input_schema=write_ttrpg_setting, output_schema=write_ttrpg_story\n",
    ")\n",
    "\n",
    "print(orjson.dumps(response_story, option=orjson.OPT_INDENT_2).decode())"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have a structured output, we can output it like a story, with custom and consistent formatting!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-style: italic\">The sun rises over the golden shores of Pythos, casting a </span>\n",
       "<span style=\"font-style: italic\">warm glow on the city of Pythopolis. The bustling metropolis</span>\n",
       "<span style=\"font-style: italic\">is a hub of technology and beach volleyball, where the Code </span>\n",
       "<span style=\"font-style: italic\">Warriors, a group of talented programmers and volleyball </span>\n",
       "<span style=\"font-style: italic\">enthusiasts, reside. In the heart of the city, the Code </span>\n",
       "<span style=\"font-style: italic\">Warriors' headquarters stands tall, a symbol of their </span>\n",
       "<span style=\"font-style: italic\">dedication to both software development and sports. Inside, </span>\n",
       "<span style=\"font-style: italic\">Aurora, a talented Python developer, and Blaze, a wise </span>\n",
       "<span style=\"font-style: italic\">volleyball coach, prepare for a fateful meeting that will </span>\n",
       "<span style=\"font-style: italic\">change their lives forever.</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[3mThe sun rises over the golden shores of Pythos, casting a \u001b[0m\n",
       "\u001b[3mwarm glow on the city of Pythopolis. The bustling metropolis\u001b[0m\n",
       "\u001b[3mis a hub of technology and beach volleyball, where the Code \u001b[0m\n",
       "\u001b[3mWarriors, a group of talented programmers and volleyball \u001b[0m\n",
       "\u001b[3menthusiasts, reside. In the heart of the city, the Code \u001b[0m\n",
       "\u001b[3mWarriors' headquarters stands tall, a symbol of their \u001b[0m\n",
       "\u001b[3mdedication to both software development and sports. Inside, \u001b[0m\n",
       "\u001b[3mAurora, a talented Python developer, and Blaze, a wise \u001b[0m\n",
       "\u001b[3mvolleyball coach, prepare for a fateful meeting that will \u001b[0m\n",
       "\u001b[3mchange their lives forever.\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Aurora</span>: Blaze, I've been following your coaching career for \n",
       "years. Your innovative techniques have revolutionized the \n",
       "game of beach volleyball. I want to combine my programming \n",
       "skills with my love for volleyball, and I believe you can \n",
       "help me become the best.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mAurora\u001b[0m: Blaze, I've been following your coaching career for \n",
       "years. Your innovative techniques have revolutionized the \n",
       "game of beach volleyball. I want to combine my programming \n",
       "skills with my love for volleyball, and I believe you can \n",
       "help me become the best.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Blaze</span>: Ah, Aurora, I've heard of your coding prowess. Your \n",
       "Python skills are legendary in the tech industry. If you're \n",
       "willing to put in the work, I can help you unlock the true \n",
       "potential of beach volleyball. Together, we can create a new\n",
       "era of sports technology.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mBlaze\u001b[0m: Ah, Aurora, I've heard of your coding prowess. Your \n",
       "Python skills are legendary in the tech industry. If you're \n",
       "willing to put in the work, I can help you unlock the true \n",
       "potential of beach volleyball. Together, we can create a new\n",
       "era of sports technology.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Aurora</span>: I'm ready to dive in, Blaze. I want to use Python to\n",
       "analyze the game, develop new strategies, and push the \n",
       "boundaries of what's possible on the court.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mAurora\u001b[0m: I'm ready to dive in, Blaze. I want to use Python to\n",
       "analyze the game, develop new strategies, and push the \n",
       "boundaries of what's possible on the court.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Blaze</span>: Then we shall embark on this journey together, \n",
       "Aurora. But first, we must gather a team of like-minded \n",
       "individuals who share our passion for both programming and \n",
       "beach volleyball.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mBlaze\u001b[0m: Then we shall embark on this journey together, \n",
       "Aurora. But first, we must gather a team of like-minded \n",
       "individuals who share our passion for both programming and \n",
       "beach volleyball.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-style: italic\">Aurora and Blaze set out on a quest to recruit the most </span>\n",
       "<span style=\"font-style: italic\">talented individuals in Pythopolis. They scour the tech </span>\n",
       "<span style=\"font-style: italic\">hubs, beachside cafes, and coding competitions, seeking </span>\n",
       "<span style=\"font-style: italic\">those who possess the perfect blend of coding skills and </span>\n",
       "<span style=\"font-style: italic\">volleyball prowess. After weeks of searching, they finally </span>\n",
       "<span style=\"font-style: italic\">assemble a team of four exceptional individuals who are </span>\n",
       "<span style=\"font-style: italic\">ready to join their cause.</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[3mAurora and Blaze set out on a quest to recruit the most \u001b[0m\n",
       "\u001b[3mtalented individuals in Pythopolis. They scour the tech \u001b[0m\n",
       "\u001b[3mhubs, beachside cafes, and coding competitions, seeking \u001b[0m\n",
       "\u001b[3mthose who possess the perfect blend of coding skills and \u001b[0m\n",
       "\u001b[3mvolleyball prowess. After weeks of searching, they finally \u001b[0m\n",
       "\u001b[3massemble a team of four exceptional individuals who are \u001b[0m\n",
       "\u001b[3mready to join their cause.\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Aurora</span>: Welcome, my fellow Code Warriors! Together, we will \n",
       "combine the power of Python programming and the art of beach\n",
       "volleyball to achieve greatness. Introduce yourselves, and \n",
       "let us know how you plan to contribute to our mission.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mAurora\u001b[0m: Welcome, my fellow Code Warriors! Together, we will \n",
       "combine the power of Python programming and the art of beach\n",
       "volleyball to achieve greatness. Introduce yourselves, and \n",
       "let us know how you plan to contribute to our mission.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Samurai</span>: I am Samurai, a master of precision and discipline.\n",
       "My coding skills are unmatched, and my agility on the \n",
       "volleyball court is unparalleled. With my strategic mind and\n",
       "lightning-fast reflexes, I will ensure victory for our team.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mSamurai\u001b[0m: I am Samurai, a master of precision and discipline.\n",
       "My coding skills are unmatched, and my agility on the \n",
       "volleyball court is unparalleled. With my strategic mind and\n",
       "lightning-fast reflexes, I will ensure victory for our team.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Pixel</span>: Greetings, Code Warriors! I am Pixel, the \n",
       "pixel-perfect programmer. My attention to detail and \n",
       "creative problem-solving abilities make me a valuable asset \n",
       "to any team. On the volleyball court, my quick thinking and \n",
       "adaptability will outwit our opponents.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mPixel\u001b[0m: Greetings, Code Warriors! I am Pixel, the \n",
       "pixel-perfect programmer. My attention to detail and \n",
       "creative problem-solving abilities make me a valuable asset \n",
       "to any team. On the volleyball court, my quick thinking and \n",
       "adaptability will outwit our opponents.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Nebula</span>: I am Nebula, a cosmic coder with a passion for the \n",
       "stars and the digital realm. My expertise lies in data \n",
       "analysis and visualization. I will harness the power of \n",
       "Python to uncover hidden patterns in our opponents' \n",
       "strategies and guide us to victory.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mNebula\u001b[0m: I am Nebula, a cosmic coder with a passion for the \n",
       "stars and the digital realm. My expertise lies in data \n",
       "analysis and visualization. I will harness the power of \n",
       "Python to uncover hidden patterns in our opponents' \n",
       "strategies and guide us to victory.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Blitz</span>: Greetings, Code Warriors! I am Blitz, the \n",
       "lightning-fast developer. My coding speed is unmatched, and \n",
       "my agility on the volleyball court is electrifying. With my \n",
       "lightning-quick reflexes and powerful spikes, I will leave \n",
       "our opponents in awe.\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mBlitz\u001b[0m: Greetings, Code Warriors! I am Blitz, the \n",
       "lightning-fast developer. My coding speed is unmatched, and \n",
       "my agility on the volleyball court is electrifying. With my \n",
       "lightning-quick reflexes and powerful spikes, I will leave \n",
       "our opponents in awe.\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "c = Console(width=60, highlight=False)\n",
    "\n",
    "for event in response_story[\"events\"]:\n",
    "    data = event[\"data\"]\n",
    "    if event[\"type\"] == \"setting\":\n",
    "        c.print(data[\"description\"], style=\"italic\")\n",
    "    if event[\"type\"] == \"conversation\":\n",
    "        c.print(f\"[b]{data['character_name']}[/b]: {data['dialogue']}\")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MIT License\n",
    "\n",
    "Copyright (c) 2023 Max Woolf\n",
    "\n",
    "Permission is hereby granted, free of charge, to any person obtaining a copy\n",
    "of this software and associated documentation files (the \"Software\"), to deal\n",
    "in the Software without restriction, including without limitation the rights\n",
    "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n",
    "copies of the Software, and to permit persons to whom the Software is\n",
    "furnished to do so, subject to the following conditions:\n",
    "\n",
    "The above copyright notice and this permission notice shall be included in all\n",
    "copies or substantial portions of the Software.\n",
    "\n",
    "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
    "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
    "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n",
    "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
    "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n",
    "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n",
    "SOFTWARE."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
